﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using OBDUDSUtils.CNNMode;
using OBDUDSUtils.Common;

namespace OBDUDSUtils.Mongoose
{
    public class MongooseManage
    {
        public delegate void MonOBDMessage(List<CANBasic.VCI_CAN_OBJ> data);
        public  event MonOBDMessage MonOBDMessageEvent;
        public  event MonOBDMessage MonOBDMessageEvents
        {
            add
            {
                if (MonOBDMessageEvent == null)
                {
                    MonOBDMessageEvent += value;
                }
            }
            remove
            {
                MonOBDMessageEvent -= value;
            }
        }

        private System.Timers.Timer revTimer;//定时器自动读取数据
        private DiagData mgData;//存储设备数据
        public List<DiagMessageData> _OBDMessageDatas;//存储OBD报文
        private void MonSendOBDResult(List<CANBasic.VCI_CAN_OBJ> data)
        {
            MonOBDMessageEvent(data);
        }

        /// <summary>
        /// 初始化CAN
        /// </summary>
        /// <param name="device"></param>
        public void InitCANDevice(ref DiagData diagData)
        {
            mgData = diagData;
            _OBDMessageDatas = new List<DiagMessageData>();

            revTimer = new System.Timers.Timer();
            revTimer.Interval = 5;
            revTimer.Enabled = false;
            revTimer.Elapsed += RevTimer_Elapsed;
        }

        /// <summary>
        /// 启动设备:初始化+连接设备
        /// </summary>
        ///<param name="device"></param>
        public void OpenMongoose(ref DiagData device)
        {
            if (device.MongooseDevice.MongooseConnected)//已连接设备
                return;
            //初始化设备
            uint deviceID = device.MongooseDevice.DeviceID;
            var status = Mongoose.MonOpen(device.MongooseDevice.DeviceName, ref deviceID);
            device.MongooseDevice.DeviceID = deviceID;

            if (status == RES_MONGOOSE_HEX.STATUS_NOERROR)//初始化设备成功
            {
                uint channelID = 0;
                status = Mongoose.MonConnect(device.MongooseDevice.DeviceID, (uint)device.MongooseDevice.ProtocolID, device.MongooseDevice.Flags, device.MongooseDevice.BaudRate, ref channelID);
                device.MongooseDevice.ChannelID = channelID;

                if (status == RES_MONGOOSE_HEX.STATUS_NOERROR)//连接设备成功
                {
                    device.MongooseDevice.MongooseConnected = true;
                    revTimer.Enabled = true;
                    LogHelper.Log.Info("【Mongoose】连接设备成功");
                }
                else
                {
                    device.MongooseDevice.MongooseConnected = false;
                    LogHelper.Log.Info("【Mongoose】连接设备失败");
                }
            }
            else
            {
                LogHelper.Log.Info("【Mongoose】初始化设备失败");
            }
        }

        /// <summary>
        /// 关闭设备：断开连接+关闭设备
        /// </summary>
        public void CloseMongoose(ref DiagData device)
        {
            if (!device.MongooseDevice.MongooseConnected)
            {
                return;
            }
            var status = Mongoose.MonDisconnect(device.MongooseDevice.ChannelID);
            if (status == RES_MONGOOSE_HEX.STATUS_NOERROR)
            {
                LogHelper.Log.Info("【Mongoose】已断开与车辆网络的连接");
                status = Mongoose.MonClose(device.MongooseDevice.DeviceID);
                if (status == RES_MONGOOSE_HEX.STATUS_NOERROR)
                {
                    device.MongooseDevice.MongooseConnected = false;
                    revTimer.Enabled = false;
                    LogHelper.Log.Info("【Mongoose】已关闭与设备的连接！");
                }
                else
                {
                    LogHelper.Log.Info("【Mongoose】关闭与设备的连接失败!");
                }
            }
            else
            {
                LogHelper.Log.Info("【Mongoose】断开与车辆网络的连接失败");
            }
        }

        /// <summary>
        /// 启动过滤
        /// </summary>
        /// <param name="device"></param>
        /// <returns></returns>
        public bool StartMsgFilter(MongooseConfig device)
        {
            PassthruMsg pMaskMsg = new PassthruMsg();
            pMaskMsg.ProtocolID = device.ProtocolID;
            pMaskMsg.DataSize = 4;
            if (pMaskMsg.ProtocolID == (uint)ProtocolType.ISO15765)
            {
                pMaskMsg.TxFlags = MongooseConfig.ISO15765_FRAME_PAD;
            }
            else if (pMaskMsg.ProtocolID == (uint)ProtocolType.ISO14230)
            {
                pMaskMsg.TxFlags = 0;
            }

            PassthruMsg pPatternMsg = new PassthruMsg();
            pPatternMsg.ProtocolID = (uint)device.ProtocolID;
            if (pPatternMsg.ProtocolID == (uint)ProtocolType.ISO15765)
            { 
                pPatternMsg.TxFlags = MongooseConfig.ISO15765_FRAME_PAD; 
            }
            else
            { 
                pPatternMsg.TxFlags = 0; 
            }
            pPatternMsg.DataSize = 4;
            pPatternMsg.Data[0] = 0;
            pPatternMsg.Data[1] = 0;
            pPatternMsg.Data[2] = 7;
            pPatternMsg.Data[3] = 0xe8;

            var status = Mongoose.MonIcotl(device.ChannelID, MongooseConfig.CLEAR_RX_BUFFER, new IntPtr(0), new IntPtr(0));
            status = Mongoose.MonIcotl(device.ChannelID, MongooseConfig.CLEAR_TX_BUFFER, new IntPtr(0), new IntPtr(0));

            PassthruMsg pFlowControlMsg = new PassthruMsg();
            pFlowControlMsg.ProtocolID = (uint)device.ProtocolID;
            pFlowControlMsg.TxFlags = MongooseConfig.ISO15765_FRAME_PAD;
            pFlowControlMsg.DataSize = 4;

            //选择的协议不同时，幅值的数据值不同
            if (pMaskMsg.ProtocolID == (uint)ProtocolType.ISO15765)
            {
                pMaskMsg.Data[0] = 0xFF;
                pMaskMsg.Data[1] = 0xFF;
                pMaskMsg.Data[2] = 0xFF;
                pMaskMsg.Data[3] = 0xFF;

                //当选择的是UDS时，过滤ID
                pFlowControlMsg.Data[0] = 0;
                pFlowControlMsg.Data[1] = 0;
                pFlowControlMsg.Data[2] = 7;
                pFlowControlMsg.Data[3] = 0xe0;
            }
            else if (pMaskMsg.ProtocolID == (uint)ProtocolType.ISO14230)
            {
                pMaskMsg.Data[0] = 0x00;
                pMaskMsg.Data[1] = 0xFF;
                pMaskMsg.Data[2] = 0xFF;
                pMaskMsg.Data[3] = 0x00;

                //当选择的是KWP时，只过滤源地址和目标地址
                pPatternMsg.Data[0] = 0x00;
                pPatternMsg.Data[1] = 0x00;//iRxID;
                pPatternMsg.Data[2] = 0x00;// iTxID;
                pPatternMsg.Data[3] = 0x00;
            }
            else
            { 
            }

            uint pMsgId = 0;
            status = Mongoose.MonStartMsgFilter(device.ChannelID, MongooseConfig.FLOW_CONTROL_FILTER, ref pMaskMsg, ref pPatternMsg, ref pFlowControlMsg, ref pMsgId);
            if (status == RES_MONGOOSE_HEX.STATUS_NOERROR)
            {
                LogHelper.Log.Info("【Mongoose】设置过滤成功");
                return true;
            }
            LogHelper.Log.Info("【Mongoose】设置过滤失败");
            return false;
        }

        public void SendMessage(MongooseConfig device, out bool resulted)
        {
            //写数据
            PassthruMsg writeStruct = new PassthruMsg();

            writeStruct.ProtocolID = (uint)device.ProtocolID;
            writeStruct.RxStatus = 0;
            if (device.ProtocolID == (uint)ProtocolType.ISO15765)
                writeStruct.TxFlags = MongooseConfig.ISO15765_FRAME_PAD;
            else
                writeStruct.TxFlags = 0x00;
            writeStruct.Timestamp = 0;
            //前4位为头
            var frameID = Convert.ToString(device.FrameID, 16).PadLeft(4, '0');
            writeStruct.Data[0] = 0x00;
            writeStruct.Data[1] = 0x00;
            writeStruct.Data[2] = Convert.ToByte(frameID.Substring(0, 2), 16);//0x07
            writeStruct.Data[3] = Convert.ToByte(frameID.Substring(2, 2), 16);//0xdf

            writeStruct.Data[4] = (byte)device.Sid;
            writeStruct.Data[5] = (byte)device.Pid;

            writeStruct.DataSize = 6;
            uint pNumMsg = 1;
            uint timeout = 100;

            var res_Icotl_tx = Mongoose.MonIcotl(device.ChannelID, MongooseConfig.CLEAR_TX_BUFFER, new IntPtr(0), new IntPtr(0));

            var res_send = Mongoose.MonWriteMsgs(device.ChannelID, ref writeStruct, ref pNumMsg, timeout);

            if (res_send != RES_MONGOOSE_HEX.STATUS_NOERROR)
            {
                resulted = false;
            }
            else
            {
                resulted = true;

                if (mgData.IsSaveMessage)
                {
                    DiagMessageData message = new DiagMessageData();
                    message.ID++;
                    message.Direction = "发送";
                    message.UpdateTime = System.DateTime.Now.ToString("yyyy.MM.dd HH:mm:ss");
                    message.FrameID = "0x" + mgData.EtasDevice.FrameID;
                    message.FrameFormat = "数据帧";
                    message.FrameType = "标准帧";
                    message.DataLength = "0x08";
                    message.FrameData = BitConverter.ToString(mgData.EtasDevice.Data).Replace("-", " ");
                    _OBDMessageDatas.Add(message);
                }
            }
        }

        public List<CANBasic.VCI_CAN_OBJ> PassThruReadMsgs(MongooseConfig device)
        {
            //多帧数据如何处理，当前仅解析了单帧数据

            List<CANBasic.VCI_CAN_OBJ> data = new List<CANBasic.VCI_CAN_OBJ>();
            PassthruMsg Msg = new PassthruMsg();
            Msg.TxFlags = MongooseConfig.ISO15765_FRAME_PAD;
            Msg.ProtocolID = (uint)device.ProtocolID;
            uint pnumMsg = 1;
            uint timeout = 100;
            var res_read = Mongoose.MonReadMsgs(device.ChannelID, ref Msg, ref pnumMsg, timeout);
            if (res_read != RES_MONGOOSE_HEX.STATUS_NOERROR)
            {
                return data;
            }
            
            CANBasic.VCI_CAN_OBJ obj = new CANBasic.VCI_CAN_OBJ();
            obj.ID = device.FrameID;//过滤设置的默认ID
            //当数据为多条时，如何获取
            for (int i = 0; i < Msg.DataSize; i++)//data[4] = 0x41
            {
                if (i >= 4)
                {
                    obj.Data[i] = Msg.Data[i];
                }
            }
            data.Add(obj);

            if (mgData.IsSaveMessage)
            {
                DiagMessageData msgData = new DiagMessageData();
                msgData.ID++;
                msgData.Direction = "接收";
                msgData.UpdateTime = System.DateTime.Now.ToString("yyyy.MM.dd HH:mm:ss");
                msgData.FrameID = "0x" + Convert.ToString(obj.ID, 16).PadLeft(8, '0');
                msgData.FrameFormat = "数据帧";
                msgData.FrameType = "标准帧";
                msgData.DataLength = "0x08";
                msgData.FrameData = BitConverter.ToString(obj.Data).Replace("-", " ");
                _OBDMessageDatas.Add(msgData);
            }
            return data;
        }

        private void RevTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
        {
            var data = PassThruReadMsgs(mgData.MongooseDevice);
            if (data.Count <= 0)
                return;
            MonSendOBDResult(data);
        }

        public void SaveMessageData(string messageFilePath)
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine(DiagMessageData.CONST_ID + DiagMessageData.CONST_SPACE + DiagMessageData.CONST_DIRECTION + DiagMessageData.CONST_SPACE + DiagMessageData.CONST_TIME + DiagMessageData.CONST_SPACE + DiagMessageData.CONST_FID + DiagMessageData.CONST_SPACE + DiagMessageData.CONST_FFORMAT + DiagMessageData.CONST_SPACE + DiagMessageData.CONST_FTYPE + DiagMessageData.CONST_SPACE + DiagMessageData.CONST_FLEN + DiagMessageData.CONST_SPACE + DiagMessageData.CONST_FDATA);

            foreach (var msg in _OBDMessageDatas)
            {
                sb.AppendLine(msg.ID.ToString() + DiagMessageData.CONST_SPACE + msg.Direction + DiagMessageData.CONST_SPACE + msg.UpdateTime + DiagMessageData.CONST_SPACE + msg.FrameID + DiagMessageData.CONST_SPACE + msg.FrameFormat + DiagMessageData.CONST_SPACE + msg.FrameType + DiagMessageData.CONST_SPACE + msg.DataLength + DiagMessageData.CONST_SPACE + msg.FrameData);
            }
            DataFile.Fault_SaveResult(sb.ToString(), messageFilePath);
        }
    }
}
